package com.hqd.ch03.v33.web.servlet.handler;


import com.hqd.ch03.v33.core.annotation.AnnotatedElementUtils;
import com.hqd.ch03.v33.web.bind.annotation.RequestMapping;
import com.hqd.ch03.v33.web.servlet.mvc.method.RequestMappingInfo;

import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.function.Predicate;

public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping {

    private Map<String, Predicate<Class<?>>> pathPrefixes = Collections.emptyMap();

    protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
        /**
         * 创建对应请求信息
         */
        RequestMappingInfo info = createRequestMappingInfo(method);
        if (info != null) {
            /**
             * 处理类上的RequestMapping
             */
            RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
            if (typeInfo != null) {
                info = typeInfo.combine(info);
            }
            String prefix = getPathPrefix(handlerType);
            if (prefix != null) {
                info = RequestMappingInfo.paths(prefix).build().combine(info);
            }
        }
        return info;
    }

    String getPathPrefix(Class<?> handlerType) {
        for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
            if (entry.getValue().test(handlerType)) {
                return entry.getKey();
            }
        }
        return null;
    }

    public Map<String, Predicate<Class<?>>> getPathPrefixes() {
        return this.pathPrefixes;
    }

    public void setPathPrefixes(Map<String, Predicate<Class<?>>> prefixes) {
        this.pathPrefixes = (!prefixes.isEmpty() ?
                Collections.unmodifiableMap(new LinkedHashMap<>(prefixes)) :
                Collections.emptyMap());
    }

    private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
        RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
        return (requestMapping != null ? createRequestMappingInfo(requestMapping) : null);
    }

    protected RequestMappingInfo createRequestMappingInfo(
            RequestMapping requestMapping) {

        RequestMappingInfo.Builder builder = RequestMappingInfo.
                paths(requestMapping.value())
                .methods(requestMapping.method());
        return builder.build();
    }

    public void init(Object obj) {
        detectHandlerMethods(obj);
    }
}
